package cn.kgc.commons.advice;

import cn.kgc.commons.annotation.LimitAnnotation;
import cn.kgc.commons.exception.HttpException;
import cn.kgc.commons.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * <p></p>
 *
 * @author 李孟鸠
 * @Date: 2023年02月09日8:34
 */
@Aspect
@Component
@Slf4j
public class LimitAdvice {
    @Resource
    private RedisUtil redisUtil;
    @Pointcut("@annotation(cn.kgc.commons.annotation.LimitAnnotation)")
    public void limitPointCut(){}

    @Around("limitPointCut()")
    public Object autoLogAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName =
                ((MethodSignature) joinPoint.getSignature()).getMethod().getName();
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr(); //ip地址的工具类
        log.info("接口限流:类名[{}],方法名[{}],ip地址:{}",className,methodName,ip);
        LimitAnnotation limitAnnotation =
                ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(LimitAnnotation.class);
        int limit = limitAnnotation.limit(); //单位时间内，接口被访问的次数
        int times = limitAnnotation.times(); //单位时间，秒
        String msg = limitAnnotation.msg(); //错误信息
        //redis的key
        String key=ip+"_"+className+"_"+methodName;
        //判断redis中是否有key 如果没有 将这个key的值改为1
        boolean result = redisUtil.setIfAbsent(key, 1, times, TimeUnit.SECONDS);
        if (!result){
            int temp = (Integer) redisUtil.get(key); //方法已经点击的次数
            if (temp>=limit){
                log.info("接口限流:类名[{}],方法名[{}],ip地址:{}",msg);
                throw new HttpException(90003,500);
            }
            redisUtil.incrment(key); //如果没有达到上限，访问次数+1
        }
        Object proceed = joinPoint.proceed();//执行方法
        return proceed;
    }
}
